/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include "lvgl.h"
#include "hmi_ctrl_center.h"
#include "hmi_conf.h"
#include "hmi_subject.h"
#include "hmi_theme.h"
#include "hmi_asset.h"
#include "hmi_pg_navigation.h"
#include "hmi_pages.h"

/*********************
 *      DEFINES
 *********************/
#define HMI_CTRL_CENTER_ATUO_DOWN_THRESH LV_DPX(20)

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void status_bar_pressing_cb(lv_event_t *e);
static void time_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void wifi_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void bluetooth_time_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject);
static void time_anim_exec_cb(void *obj, int32_t val);
static void time_anim_cplt_cb(lv_anim_t *a);
static void time_anim_start_cb(lv_anim_t *a);
static void status_bar_hide_time(bool hidden);
static void pg_stack_ops_cb();

/**********************
 *  STATIC VARIABLES
 **********************/
static lv_obj_t *status_bar;
static lv_obj_t *time;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
void hmi_status_bar_init()
{
    lv_obj_add_style(lv_layer_top(), &hmi_g_wrap_style, 0);

    status_bar = lv_obj_create(lv_layer_top());
    lv_obj_move_background(status_bar);
    lv_obj_remove_style_all(status_bar);
    lv_obj_set_size(status_bar, lv_pct(100), lv_pct(12));
    lv_obj_add_event_cb(status_bar, status_bar_pressing_cb, LV_EVENT_ALL, NULL);

    lv_obj_set_style_pad_hor(status_bar, 10, 0);
    lv_obj_set_style_pad_column(status_bar, 5, 0);
    lv_obj_set_style_base_dir(status_bar, LV_BASE_DIR_RTL, 0);
    lv_obj_set_flex_flow(status_bar, LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(status_bar, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);

    lv_obj_update_layout(status_bar);
    int32_t font_height = lv_obj_get_height(status_bar) * 0.7;

    time = lv_label_create(status_bar);
    lv_obj_add_flag(time, LV_OBJ_FLAG_IGNORE_LAYOUT);
    lv_obj_align(time, LV_ALIGN_LEFT_MID, 0, 0);
    lv_obj_set_style_text_font(time, hmi_ttf_create_static("def_font", font_height, 0), 0);
    lv_obj_add_flag(time, LV_OBJ_FLAG_HIDDEN);

    lv_obj_t *wifi_icon = lv_image_create(status_bar);
    lv_obj_add_style(wifi_icon, &hmi_g_icon_style, 0);
    lv_image_set_scale(wifi_icon, 200 * HMI_PNG_ZOOM_RATE);

    lv_obj_t *bluetooth_icon = lv_image_create(status_bar);
    lv_obj_add_style(bluetooth_icon, &hmi_g_icon_style, 0);
    lv_image_set_scale(bluetooth_icon, 200 * HMI_PNG_ZOOM_RATE);
    lv_image_set_src(bluetooth_icon, hmi_png("bluetooth_slash"));

    lv_subject_add_observer_obj(&hmi_time_subj, time_subj_observer_cb, time, NULL);
    lv_subject_add_observer_obj(&hmi_wifi_subj, wifi_subj_observer_cb, wifi_icon, NULL);
    lv_subject_add_observer_obj(&hmi_bluetooth_subj, bluetooth_time_subj_observer_cb, bluetooth_icon, NULL);

    hmi_add_push_cplt_cb(pg_stack_ops_cb);
    hmi_add_pop_cplt_cb(pg_stack_ops_cb);
    hmi_add_back_home_cplt_cb(pg_stack_ops_cb);
}

int32_t hmi_status_bar_height()
{
    lv_obj_update_layout(status_bar);
    return lv_obj_get_height(status_bar);
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void status_bar_pressing_cb(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);

    lv_obj_t *ctrl_center = hmi_get_ctrl_center_obj();
    int32_t height = lv_obj_get_height(ctrl_center);

    lv_point_t point;
    lv_indev_get_point(lv_indev_active(), &point);

    switch (code)
    {
    case LV_EVENT_PRESSING:
        if (point.y >= height)
            hmi_ctrl_center_down();
        else
            lv_obj_set_y(ctrl_center, point.y - height);
        break;

    case LV_EVENT_RELEASED:
        if (point.y >= HMI_CTRL_CENTER_ATUO_DOWN_THRESH)
            hmi_ctrl_center_down();
        else
            hmi_ctrl_center_up();

    default:
        break;
    }
}

static void time_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target(observer);

    lv_subject_t *hour_subj = lv_subject_get_group_element(subject, 4);
    lv_subject_t *minute_subj = lv_subject_get_group_element(subject, 5);

    int32_t hour = lv_subject_get_int(hour_subj);
    int32_t minute = lv_subject_get_int(minute_subj);

    lv_label_set_text_fmt(obj, "%02d:%02d", hour, minute);
}

static void wifi_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target(observer);

    int32_t state = lv_subject_get_int(subject);
    if (state == HMI_STATE_OFF)
        lv_image_set_src(obj, hmi_png("wifi_slash"));
    else
        lv_image_set_src(obj, hmi_png("wifi"));
}

static void bluetooth_time_subj_observer_cb(lv_observer_t *observer, lv_subject_t *subject)
{
    lv_obj_t *obj = lv_observer_get_target(observer);

    int32_t state = lv_subject_get_int(subject);
    if (state == HMI_STATE_OFF)
        lv_image_set_src(obj, hmi_png("bluetooth_slash"));
    else
        lv_image_set_src(obj, hmi_png("bluetooth"));
}

static void time_anim_exec_cb(void *obj, int32_t val)
{
    lv_obj_set_style_opa(obj, val, 0);
}

static void time_anim_cplt_cb(lv_anim_t *a)
{
    LV_UNUSED(a);

    lv_obj_add_flag(time, LV_OBJ_FLAG_HIDDEN);
}

static void time_anim_start_cb(lv_anim_t *a)
{
    LV_UNUSED(a);

    lv_obj_remove_flag(time, LV_OBJ_FLAG_HIDDEN);
}

static void status_bar_hide_time(bool hidden)
{
    bool is_hidden = lv_obj_has_flag(time, LV_OBJ_FLAG_HIDDEN);

    lv_anim_t a;
    lv_anim_init(&a);
    lv_anim_set_var(&a, time);
    lv_anim_set_duration(&a, 500 * hmi_g_anim_rate);
    lv_anim_set_exec_cb(&a, time_anim_exec_cb);
    lv_anim_set_path_cb(&a, lv_anim_path_ease_out);

    if (hidden && !is_hidden)
    {
        lv_anim_set_values(&a, LV_OPA_COVER, LV_OPA_TRANSP);
        lv_anim_set_completed_cb(&a, time_anim_cplt_cb);
        lv_anim_start(&a);
    }
    else if (!hidden && is_hidden)
    {
        lv_anim_set_values(&a, LV_OPA_TRANSP, LV_OPA_COVER);
        lv_anim_set_start_cb(&a, time_anim_start_cb);
        lv_anim_start(&a);
    }
}

static void pg_stack_ops_cb()
{
    hmi_pg_t *pg_cur = hmi_get_cur_page();
    hmi_pg_t *pg_home = hmi_pg_home();

    if (pg_cur && pg_home && (pg_cur == pg_home))
        status_bar_hide_time(1);
    else
        status_bar_hide_time(0);
}
